package com.xtayfjpk.security;

import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class SignatureTest {
	private static final String KEY_PAIR_ALGOGRITHM = "DSA";
	private static final String SIGNATURE_ALGOGRITHM = "SHA1withDSA";
	private static final String PUBLIC_KEY_PATH = "public.key";
	private static final String PRIVATE_KEY_PATH = "private.key";
	private static final String SIGNATURE_PATH = "signature.dat";
	
	
	@Test
	public void testGenerateKeyPair() throws Exception {
		KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_PAIR_ALGOGRITHM);
		KeyPair keyPair = generator.generateKeyPair();
		PublicKey publicKey = keyPair.getPublic();
		PrivateKey privateKey = keyPair.getPrivate();
		
		writeKey(PUBLIC_KEY_PATH, publicKey);
		writeKey(PRIVATE_KEY_PATH, privateKey);
	}
	
	@Test
	public void testSign() throws Exception {
		String myInfo = "我的测试信息";
		PrivateKey privateKey = PrivateKey.class.cast(readKey(PRIVATE_KEY_PATH));
		//初始化一个Signature对象，并用私钥对信息签名
		Signature signature = Signature.getInstance(SIGNATURE_ALGOGRITHM);
		//私钥签名
		signature.initSign(privateKey);
		//更新待签名数据
		signature.update(myInfo.getBytes());
		//得到数字签名
		byte[] signed = signature.sign();
		
		//把信息和签名保存在一个文件中
		writeObjects(SIGNATURE_PATH, myInfo, signed);
	}
	
	@Test
	public void testVerify() throws Exception {
		PublicKey publicKey = PublicKey.class.cast(readKey(PUBLIC_KEY_PATH));
		
		List<Object> objects = readObjects(SIGNATURE_PATH);
		String info = String.class.cast(objects.get(0));
		byte[] signed = byte[].class.cast(objects.get(1));
		
		//初始化签名引擎类
		Signature signature = Signature.getInstance(SIGNATURE_ALGOGRITHM);
		//公钥用于验证签名
		signature.initVerify(publicKey);
		//更新待待签名验证数据
		signature.update(info.getBytes());
		//测试签名是否正确
		if(signature.verify(signed)) {
			System.out.println("签名正确");
		}
	}
	public void writeKey(String path, Key key) throws Exception {
		FileOutputStream fos = new FileOutputStream(path);
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(key);
		oos.close();
	}
	
	public Key readKey(String path) throws Exception {
		FileInputStream fis = new FileInputStream(path);
		ObjectInputStream bis = new ObjectInputStream(fis);
		Object object = bis.readObject();
		bis.close();
		return (Key) object;
	}
	
	public void writeObjects(String path, Serializable... objects) throws Exception {
		if(objects!=null) {
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
			for(Serializable object : objects) {
				oos.writeObject(object);
			}
			oos.close();
		}
	}
	
	public List<Object> readObjects(String path) throws Exception {
		List<Object> objects = new ArrayList<>();
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
		
		boolean flag = true;
		while(flag) {
			try {
				objects.add(ois.readObject());
			} catch (EOFException e) {
				//表示流中已无对象可读
				break;
			}
		}
		ois.close();
		return objects;
	}
	
	
	//对于密钥的保存可以使用对象流的方式保存和传送的 , 也可可以用编码的方式保存
	@Test
	public void testEncodeKey() throws Exception {
		PublicKey publicKey = null;
		byte[] encodedPublicKey = publicKey.getEncoded();
		X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(encodedPublicKey);
		KeyFactory keyFactory = KeyFactory.getInstance("DSA");
		PublicKey readedPublicKey = keyFactory.generatePublic(x509EncodedKeySpec);
	
		PrivateKey privateKey = null;
		byte[] encodedPrivateKey = privateKey.getEncoded();
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
		KeyFactory keyFactory2 = KeyFactory.getInstance("DSA");
		PrivateKey readedPrivateKey = keyFactory2.generatePrivate(pkcs8EncodedKeySpec);
	}
}
